package com.easyOrder.core.filter;

import com.easyOrder.core.cache.IRedisCacheClient;
import com.easyOrder.core.identity.*;
import com.easyOrder.core.utils.Cryptos;
import com.google.gson.Gson;
import com.easyOrder.core.exception.api.InvalidOprationException;
import com.easyOrder.core.utils.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;


/**
 * 身份验证拦截器
 */
public class IdentityInterceptor implements HandlerInterceptor {

    private static final String IDENTITY_TOKEN_KEY = "identityToken";

    @Autowired
    private IRedisCacheClient cacheClient;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            return true;
        }
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            Gson gson = new Gson();
            if (validIdentity(request, method, gson)) return true;
            if (validDeviceIdentity(request, method, gson)) return true;
        }
        return true;
    }

    private boolean validIdentity(HttpServletRequest request, Method method, Gson gson) {
        IdentityAnnotation annotation = method.getAnnotation(IdentityAnnotation.class);
        if (null != annotation) {
            boolean needValidateToken = annotation.validateToken();
            if (needValidateToken) {
                String sessionId = WebUtils.Session.get().getId();
                String cacheKey = IdentityTokenProcessor.getCacheKey(sessionId);
                IdentityToken token = gson.fromJson(cacheClient.get(cacheKey), IdentityToken.class);
                if (null != token) {
                    if (isInvalidToken(request, token)) {
                        throw new InvalidOprationException();
                    }
                    return true;
                }
                throw new InvalidOprationException();
            }
        }
        return false;
    }

    private boolean validDeviceIdentity(HttpServletRequest request, Method method, Gson gson) {
        DeviceIdentity annotation = method.getAnnotation(DeviceIdentity.class);
        if (null != annotation) {
            boolean needValidateToken = annotation.validateToken();
            if (needValidateToken) {
                String sessionId = WebUtils.Session.get().getId();
                String cacheKey = IdentityTokenProcessor.getDeviceCacheKey(sessionId,WebUtils.Session.getDeviceId(request));
                IdentityDeviceToken token = gson.fromJson(cacheClient.get(cacheKey), IdentityDeviceToken.class);
                if (null != token) {
                    if (isInvalidDeviceToken(request, token)) {
                        throw new InvalidOprationException();
                    }
                    return true;
                }
                throw new InvalidOprationException();
            }
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

    private boolean isInvalidToken(HttpServletRequest request, IdentityToken cacheToken) {
        String requestToken = request.getHeader(IDENTITY_TOKEN_KEY);
        if (null == cacheToken || !cacheToken.getToken().equals(requestToken)) {
            return true;
        }
        String decryptString = Cryptos.aesDecrypt(IdentityTokenProcessor.hexStringToByte(requestToken),
                IdentityTokenProcessor.AES_KEY.getBytes());
        String[] tmpArray = decryptString.split("_");
        return !WebUtils.Http.getIpAddr(request).equals(tmpArray[2]);
    }

    private boolean isInvalidDeviceToken(HttpServletRequest request, IdentityDeviceToken cacheToken) {
        String requestToken = request.getHeader(IDENTITY_TOKEN_KEY);
        if (null == cacheToken || !cacheToken.getToken().equals(requestToken)) {
            return true;
        }
        String decryptString = Cryptos.aesDecrypt(IdentityTokenProcessor.hexStringToByte(requestToken),
                IdentityTokenProcessor.AES_KEY.getBytes());
        String[] tmpArray = decryptString.split("_");
//        return !WebUtils.Http.getIpAddr(request).equals(tmpArray[2]) || !WebUtils.Session.getSessionId(request).equals(tmpArray[0])
//                || !WebUtils.Session.getDeviceId(request).equals(tmpArray[3]);
        return  !WebUtils.Session.getSessionId(request).equals(tmpArray[0])
                || !WebUtils.Session.getDeviceId(request).equals(tmpArray[3]);
    }
}